home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CTOOLS10.ARJ / SET.C < prev    next >
C/C++ Source or Header  |  1991-12-31  |  16KB  |  561 lines

  1. /****************************************************************************
  2. *
  3. *                    Copyright (C) 1991 Kendall Bennett.
  4. *                            All rights reserved.
  5. *
  6. * Filename:        $RCSfile: set.c $
  7. * Version:        $Revision: 1.4 $
  8. *
  9. * Language:        ANSI C
  10. * Environment:    any
  11. *
  12. * Description:    Module to implement bit oriented set maniuplation.
  13. *
  14. * $Id: set.c 1.4 91/12/31 19:40:33 kjb Exp $
  15. *
  16. * Revision History:
  17. * -----------------
  18. *
  19. * $Log:    set.c $
  20. * Revision 1.4  91/12/31  19:40:33  kjb
  21. * Modified include file directories
  22. * Revision 1.3  91/09/03  18:28:26  ROOT_DOS
  23. * Ported to UNIX.
  24. * Revision 1.2  91/09/01  01:14:33  ROOT_DOS
  25. * Changed search for include files to look in current directory
  26. * Revision 1.1  91/08/16  13:28:48  ROOT_DOS
  27. * Initial revision
  28. ****************************************************************************/
  29.  
  30. #include <stdio.h>
  31. #include <malloc.h>
  32. #include <ctype.h>
  33. #include <signal.h>
  34. #include <string.h>
  35. #include "debug.h"
  36. #include "set.h"
  37.  
  38. PUBLIC SET *newset(void)
  39. /****************************************************************************
  40. *
  41. * Function:        newset
  42. * Returns:        Pointer to the set, NULL upon error.
  43. *
  44. * Description:    Creates a new set and returns a pointer to it. If an error
  45. *                occurs, and error message is output and SIGABRT is raised.
  46. *                NULL is returned if raise() returns.
  47. *
  48. ****************************************************************************/
  49. {
  50.     SET    *p;
  51.  
  52.     if (!(p = (SET *)malloc( sizeof(SET)))) {
  53.         fprintf(stderr,"Can't get memory to create set\n");
  54.         raise(SIGABRT);
  55.         return NULL;            /* Usually won't get here */
  56.         }
  57.  
  58.     memset(p, 0, sizeof(SET));
  59.     p->map = p->defmap;
  60.     p->nwords = _DEFWORDS;
  61.     p->nbits = _DEFBITS;
  62.     return p;
  63. }
  64.  
  65. PUBLIC void delset(SET *set)
  66. /****************************************************************************
  67. *
  68. * Function:        delset
  69. * Parameters:    set        - Set to delete
  70. *
  71. * Description:    Delete's a set previously created with a call to newset.
  72. *
  73. ****************************************************************************/
  74. {
  75.     if (set->map != set->defmap)
  76.         free(set->map);
  77.     free(set);
  78. }
  79.  
  80. PUBLIC SET *dupset(SET *set)
  81. /****************************************************************************
  82. *
  83. * Function:        dupset
  84. * Parameters:    set        - Set to duplicate
  85. * Returns:        Pointer to the duplicated set
  86. *
  87. * Description:    Create a new set that has the same members as the input set.
  88. *
  89. ****************************************************************************/
  90. {
  91.     SET        *new;
  92.  
  93.     if (!(new = (SET *)malloc(sizeof(SET)))) {
  94.         fprintf(stderr,"Can't get memory to duplicate set\n");
  95.         exit(3);
  96.         }
  97.  
  98.     memset(new,0,sizeof(SET));
  99.     new->compl = set->compl;
  100.     new->nwords = set->nwords;
  101.     new->nbits = set->nbits;
  102.  
  103.     if (set->map == set->defmap) {                /* Default bit map in use */
  104.         new->map = new->defmap;
  105.         memcpy(new->defmap,set->defmap, _DEFWORDS * sizeof(_SETTYPE));
  106.         }
  107.     else {
  108.         new->map = (_SETTYPE *)malloc(set->nwords * sizeof(_SETTYPE));
  109.         if (!new->map) {
  110.             fprintf(stderr,"Can't get memory to duplicate set bit map\n");
  111.             exit(3);
  112.             }
  113.         memcpy(new->map, set->map, set->nwords * sizeof(_SETTYPE));
  114.         }
  115.     return new;
  116. }
  117.  
  118. PRIVATE void enlarge(int need,SET *set)
  119. /****************************************************************************
  120. *
  121. * Function:        enlarge
  122. * Parameters:    need    - Number of words required (total)
  123. *                set        - The set to enlarge
  124. *
  125. * Description:    Enlarge the set to "need" words, filling in the extre words
  126. *                with zeros. Prints an error message and aborts by calling
  127. *                exit() if there's not enough memory. This routine calls
  128. *                malloc and is hence slow and should be avoided. if possible.
  129. *
  130. ****************************************************************************/
  131. {
  132.     _SETTYPE    *new;
  133.  
  134.     if (!set || need <= set->nwords)
  135.         return;
  136.  
  137.     D(printf("enlarging %d word map to %d words\n", set->nwords,need);)
  138.  
  139.     if ( !(new = (_SETTYPE *) malloc(need * sizeof(_SETTYPE))) ) {
  140.         fprintf(stderr,"Can't get memory to expand set\n");
  141.         exit(1);
  142.         }
  143.     memcpy(new, set->map, set->nwords * sizeof(_SETTYPE));
  144.     memset(new + set->nwords, 0, (need - set->nwords) * sizeof(_SETTYPE));
  145.  
  146.     if (set->map != set->defmap)
  147.         free(set->map);
  148.  
  149.     set->map = new;
  150.     set->nwords = (unsigned char)need;
  151.     set->nbits = need * _BITS_IN_WORD;
  152. }
  153.  
  154. PUBLIC int _addset(SET *set,int bit)
  155. /****************************************************************************
  156. *
  157. * Function:        addset
  158. * Parameters:    set        - Set to add element to
  159. *                bit        - Element to add to the set
  160. *
  161. * Description:    Called by the ADD() macro when the set isn't big enough to
  162. *                hold the element being added. It exands the set to the
  163. *                necessary size and sets the indicated bit.
  164. *
  165. ****************************************************************************/
  166. {
  167.     enlarge(_ROUND(bit),set);
  168.     return _GBIT(set,bit, |= );
  169. }
  170.  
  171. PUBLIC int num_ele(SET *set)
  172. /****************************************************************************
  173. *
  174. * Function:        num_ele
  175. * Parameters:    set        - Set to determine cardinality of
  176. * Returns:        Cardinality of the set (number of elements)
  177. *
  178. * Description:    Returns the number of element (nonzero bits) in the set.
  179. *                NULL sets are considered empty. nbits[] is indexed by any
  180. *                number in the range 0-255, and it evalulates to the number
  181. *                of bits in the number.
  182. *
  183. ****************************************************************************/
  184. {
  185.     static unsigned char nbits[] = {
  186.         /*   0-15  */    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
  187.         /*  16-31  */    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  188.         /*  32-47  */    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  189.         /*  48-63  */    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  190.         /*  64-79  */    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  191.         /*  80-95  */    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  192.         /*  96-111 */    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  193.         /* 112-127 */    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  194.         /* 128-143 */    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  195.         /* 144-159 */    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  196.         /* 160-175 */    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  197.         /* 176-191 */    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  198.         /* 192-207 */    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  199.         /* 208-223 */    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  200.         /* 224-239 */    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  201.         /* 240-255 */    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
  202.         };
  203.  
  204.     int                i;
  205.     unsigned int    count = 0;
  206.     unsigned char    *p;
  207.  
  208.     if (!set)
  209.         return 0;
  210.  
  211.     p = (unsigned char *)set->map;
  212.  
  213.     for( i = _BYTES_IN_ARRAY(set->nwords); --i >= 0 ;)
  214.         count += nbits[*p++];
  215.  
  216.     return count;
  217. }
  218.  
  219. PUBLIC int _set_test(SET *set1,SET *set2)
  220. /****************************************************************************
  221. *
  222. * Function:        _set_test
  223. * Parameters:    set1    - First set to test
  224. *                set2    - Second set to test
  225. * Returns:        Result of the test
  226. *
  227. * Description:    Compares two sets. Returns the following codes:
  228. *
  229. *                     _SET_EQUIV        Sets are equivalent
  230. *                    _SET_INTER        Sets intersect but aren't equivalent
  231. *                    _SET_DISJ        Sets are disjoint
  232. *
  233. *                The smaller set is made larger if the two sets are of
  234. *                differing sizes.
  235. *
  236. ****************************************************************************/
  237. {
  238.     int            i, rval = _SET_EQUIV;
  239.     int            intersect = 0;
  240.     _SETTYPE    *p1,*p2;
  241.  
  242.     i = max( set1->nwords, set2->nwords);
  243.  
  244.     enlarge(i,set1);            /* Make the sets the same size */
  245.     enlarge(i,set2);
  246.  
  247.     p1 = set1->map;
  248.     p2 = set2->map;
  249.  
  250.     for (; --i >= 0; p1++,p2++) {
  251.         if (*p1 != *p2) {
  252.             /* You get here if the sets aren't equivalent. You can return
  253.              * immediately if the sets intersect but have to keep going in
  254.              * the case of disjoint sets (because the sets might actually
  255.              * intersect at some byte, as yet unseen).
  256.              */
  257.  
  258.             if (intersect || (*p1 & *p2))
  259.                 return _SET_INTER;
  260.             else
  261.                 rval = _SET_DISJ;
  262.             }
  263.         else {
  264.             /* If the words that we are currently testing are equal, then
  265.              * we must test whether they actually contain members. If they
  266.              * do, then we must assume that they also intersect (equivalent
  267.              * sets that are not empty MUST intersect!). Then we can test
  268.              * this value above, to ensure that we return with a value of
  269.              * _SET_INTER even when the sets intersect at words previously
  270.              * checked, and not in the word we are currently checking!
  271.              */
  272.  
  273.             intersect = (*p1 != 0) || intersect;
  274.             }
  275.         }
  276.  
  277.     return rval;                /* They're equivalent or disjoint */
  278. }
  279.  
  280. PUBLIC int setcmp(SET *set1,SET *set2)
  281. /****************************************************************************
  282. *
  283. * Function:        setcmp
  284. * Parameters:    set1    - First set to compare
  285. *                set2    - Second set to compare
  286. * Returns:        0 if sets are equivalent, < 0 if set1 < set2 and > 0 if
  287. *                set1 > set2.
  288. *
  289. * Description:    Another comparison function. This works like strcmp().
  290. *                Useful for quickly comparing sets for tree's etc.
  291. *
  292. ****************************************************************************/
  293. {
  294.     int            i,j;
  295.     _SETTYPE    *p1,*p2;
  296.  
  297.     i = j = min(set1->nwords,set2->nwords);
  298.  
  299.     for (p1 = set1->map, p2 = set2->map; --j >= 0; p1++,p2++)
  300.         if (*p1 != *p2)
  301.             return *p1 - *p2;
  302.  
  303.     /* You get here only if all words that exist in both sets are the same.
  304.      * Check the tail end of the larger array for all zeros.
  305.      */
  306.  
  307.     if ( (j = set1->nwords - i) > 0) {        /* Set1 is the larger */
  308.         while(--j >= 0)
  309.             if (*p1++)
  310.                 return 1;
  311.         }
  312.     else if ( (j = set2->nwords - i) > 0) {    /* Set2 is the larger */
  313.         while (--j >= 0);
  314.             if (*p2++)
  315.                 return -1;
  316.         }
  317.  
  318.     return 0;                                /* They're equivalent */
  319. }
  320.  
  321. PUBLIC unsigned sethash(SET *set)
  322. /****************************************************************************
  323. *
  324. * Function:        sethash
  325. * Parameters:    set        - Set to hash
  326. * Returns:        Hash value for the set.
  327. *
  328. * Description:    Finds the hash value for the set by summing together the
  329. *                words in the bit map.
  330. *
  331. ****************************************************************************/
  332. {
  333.     _SETTYPE    *p;
  334.     unsigned    total;
  335.     int            j;
  336.  
  337.     total = 0;
  338.     j = set->nwords;
  339.     p = set->map;
  340.  
  341.     while (--j >= 0)
  342.         total += *p++;
  343.  
  344.     return total;
  345. }
  346.  
  347. PUBLIC int subset(SET *set, SET *possible_subset)
  348. /****************************************************************************
  349. *
  350. * Function:        subset
  351. * Parameters:    set                - Superset to check with
  352. *                possible_subset    - Possible subset to check
  353. * Returns:        True if "possible_subset" is a subset of "set", 0 otherwise
  354. *
  355. * Description:    Determines if a set is a subset of another set. Empty sets
  356. *                are subsets of everythings. If the "possible_subset" is
  357. *                larger that the "set", then the extra bytes must be all
  358. *                zeros.
  359. *
  360. ****************************************************************************/
  361. {
  362.     _SETTYPE    *subsetp,*setp;
  363.     int            common;            /* This many bytes in potential subset */
  364.     int            tail;            /* This many implied 0 bytes in b */
  365.  
  366.     if (possible_subset->nwords > set->nwords) {
  367.         common = set->nwords;
  368.         tail = possible_subset->nwords - common;
  369.         }
  370.     else {
  371.         common = possible_subset->nwords;
  372.         tail = 0;
  373.         }
  374.  
  375.     subsetp = possible_subset->map;
  376.     setp = set->map;
  377.  
  378.     for (; --common >= 0; subsetp++, setp++)
  379.         if ((*subsetp & *setp) != *subsetp)
  380.             return 0;
  381.  
  382.     while (--tail >= 0)
  383.         if (*subsetp++)
  384.             return 0;
  385.  
  386.     return 1;
  387. }
  388.  
  389. PUBLIC void _set_op(int op, SET *dest, SET *src)
  390. /****************************************************************************
  391. *
  392. * Function:        _set_op
  393. * Parameters:    op        - Operation to perform
  394. *                dest    - Destination set
  395. *                src        - Source set
  396. *
  397. * Description:    Performs binary operations on the sets depending on op:
  398. *
  399. *                _UNION:            dest = union of src and dest
  400. *                _INTERSECT:        dest = intersection of src and dest
  401. *                _DIFFERENCE:    dest = symmetric difference of src and dest
  402. *                _ASSIGN:        dest = src
  403. *
  404. *                The size of the destination set is adjusted so that it's
  405. *                the same size as the source set.
  406. *
  407. ****************************************************************************/
  408. {
  409.     _SETTYPE    *d;        /* Pointer to destination map */
  410.     _SETTYPE    *s;        /* Pointer to source mape */
  411.     int            ssize;    /* # of words in src set */
  412.     int            tail;    /* dest set is this much bigger */
  413.  
  414.     ssize = src->nwords;
  415.  
  416.     if ((unsigned)dest->nwords < ssize) /* make sure dest set is at least */
  417.         enlarge(ssize,dest);            /* as big as the src set.          */
  418.  
  419.     tail = dest->nwords - ssize;
  420.     d = dest->map;
  421.     s = src->map;
  422.  
  423.     switch (op) {
  424.         case _UNION:
  425.             while (--ssize >= 0)
  426.                 *d++ |= *s++;
  427.             break;
  428.         case _INTERSECT:
  429.             while (--ssize >= 0)
  430.                 *d++ &= *s++;
  431.             while (--tail >= 0)
  432.                 *d++ = 0;
  433.             break;
  434.         case _DIFFERENCE:
  435.             while (--ssize >= 0)
  436.                 *d++ ^= *s++;
  437.             break;
  438.         case _ASSIGN:
  439.             while (--ssize >= 0)
  440.                 *d++ = *s++;
  441.             while (--tail >= 0)
  442.                 *d++ = 0;
  443.             break;
  444.         }
  445. }
  446.  
  447. PUBLIC void invert(SET *set)
  448. /****************************************************************************
  449. *
  450. * Function:        invert
  451. * Parameters:    set        - Set to invert
  452. *
  453. * Description:    Physically inverts the bits in the set. Compare with the
  454. *                COMPLEMENT() macro, which just modifies the complement bit.
  455. *
  456. ****************************************************************************/
  457. {
  458.     _SETTYPE    *p, *end;
  459.  
  460.     for (p = set->map, end = p + set->nwords; p < end; p++)
  461.         *p = ~*p;
  462. }
  463.  
  464. PUBLIC void truncate(SET *set)
  465. /****************************************************************************
  466. *
  467. * Function:        truncate
  468. * Parameters:    set        - Set to truncate
  469. *
  470. * Description:    Clears the set but also set's it back to the original,
  471. *                default size. Compare this routine to the CLEAR() macro
  472. *                which clears all the bits in the map but doesn't modify the
  473. *                size.
  474. *
  475. ****************************************************************************/
  476. {
  477.     if (set->map != set->defmap) {
  478.         free(set->map);
  479.         set->map = set->defmap;
  480.         }
  481.  
  482.     set->nwords = _DEFWORDS;
  483.     set->nbits = _DEFBITS;
  484.     memset(set->defmap, 0 , sizeof(set->defmap));
  485. }
  486.  
  487. PUBLIC int next_member(SET *set)
  488. /****************************************************************************
  489. *
  490. * Function:        next_member
  491. * Parameters:    set        - Set to return next element from
  492. * Returns:        The next element from the set (-1 if none)
  493. *
  494. * Description:    Finds and returns the next element that exists in the set.
  495. *                If "set" equals "NULL" we reset the current element. If
  496. *                "set" has changed since the last call, we reset and return
  497. *                the first element from this set.
  498. *
  499. ****************************************************************************/
  500. {
  501.     static SET    *oset = NULL;        /* "set" arg in last call */
  502.     static int    current_member = 0;    /* last accessed member of cur.set */
  503.  
  504.     if (!set)
  505.         return ( (int)(oset = NULL) );
  506.  
  507.     if (oset != set) {
  508.         oset = set;
  509.         current_member = 0;
  510.         }
  511.  
  512.     /* The increment must be put into the test because, if the TEST()
  513.      * invocation evaluates to true, then an increment on the right of a
  514.      * for() statement would never be executed.
  515.      */
  516.  
  517.     while (current_member++ < set->nbits)
  518.         if (TEST(set,current_member-1))
  519.             return(current_member-1);
  520.     return(-1);
  521. }
  522.  
  523. PUBLIC void pset(SET *set,int (*out)(void*,char*,int),void *param)
  524. /****************************************************************************
  525. *
  526. * Function:        pset
  527. * Parameters:    set        - Set to print
  528. *                out        - Routine to call for each element
  529. *                param    - Parameters to the output routine
  530. *
  531. * Description:    Prints the contents of the set in human-readable form. The
  532. *                output routine is called for each element of the set with
  533. *                the following arguments:
  534. *
  535. *                (*out)(param, "null",-1);    NULL set ("set" arg == NULL)
  536. *                (*out)(param, "empty",-2);    Empty set (no elements)
  537. *                (*out)(param, "%d ",N);        N is an element of the set
  538. *
  539. ****************************************************************************/
  540. {
  541.     int        i,did_something = 0;
  542.  
  543.     if (!set)
  544.         (*out)(param,"null",-1);
  545.     else {
  546.         next_member(NULL);
  547.         while( (i = next_member(set)) >= 0) {
  548.             did_something++;
  549.             (*out)(param,"%d ",i);
  550.             }
  551.         next_member(NULL);
  552.  
  553.         if (!did_something)
  554.             (*out)(param, "empty", -2);
  555.         }
  556. }
  557.